#include <stdio.h>
#include <semaphore.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <string.h>
#include <wait.h>

int main(int argc, char const *argv[])
{
    // 创建共享内存路径
    char *shm_value = "shm_value";
    char *shm_sem = "shm_sem";

    // 创建两个共享文件
    int value_fd = shm_open(shm_value, O_CREAT | O_RDWR, 0644);
    int sem_fd = shm_open(shm_sem, O_CREAT | O_RDWR, 0644);

    // 判断是否创建成功
    if (value_fd == -1 || sem_fd == -1)
    {
        perror("共享文件创建失败");
        exit(EXIT_FAILURE);
    }

    // 为创建的共享文件设置内存大小
    int ftruncate_value = ftruncate(value_fd, 100);
    int ftruncate_sem = ftruncate(sem_fd, sizeof(sem_t));

    if (ftruncate_value == -1 || ftruncate_sem == -1)
    {
        perror("共享文件设置内存失败");
        exit(EXIT_FAILURE);
    }

    // 映射到虚拟内存
    char *value = mmap(NULL, 100, PROT_READ | PROT_WRITE, MAP_SHARED, value_fd, 0);
    sem_t *sem = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED, sem_fd, 0);

    // 判断是否创建成功
    if (value == MAP_FAILED || sem == MAP_FAILED)
    {
        perror("共享文件映射失败");
        exit(EXIT_FAILURE);
    }

    // 映射成功 释放文件标识符
    close(value_fd);
    close(sem_fd);

    // 初始化信号了  sem,1  进程共享,0  没有信号两
    sem_init(sem, 1, 0);

    // 创建子进程
    pid_t pid = fork();
    if (pid == 0)
    {
        // 这是子进程

        // 向共享变量写入数据
        char *msg = "你是个好人";
        memcpy(value, msg, strlen(msg));

        printf("子进程向共享变量写入%s\n", msg);

        // 写入信号 释放
        sem_post(sem);
    }
    else if (pid > 0)
    {
        // 父进程
        // 等待信号两
        sem_wait(sem);

        // 读取共享内存数据
        printf("父进程从共享文件读的数据：%s\n", value);

        // 等待所以子进程结束
        wait(NULL);
    }

    // 父子都应该释放共享文件在虚拟内存上的映射
    munmap(value, 100);
    munmap(sem, sizeof(sem_t));

    if(pid > 0)
    {
        //销毁信号量
        sem_destroy(sem);
        //关闭共享文件
        shm_unlink(shm_value);
        shm_unlink(shm_sem);
    }

    return 0;
}
